﻿using System;
using PerfAnalyzerLib;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTests
{
	/// <summary>
	/// This is a test class for Counter and is intended to contain all Counter Unit Tests
	///</summary>
	[TestClass]
	public class CounterTest
	{
		/// <summary>
		/// Testing for Counter Constructor
		///</summary>
		[TestMethod]
		public void Counter_ConstructorTest()
		{
			string counterName = GeneratorCounterInfo.GenerateGenericCounterInfo(true);
			var target = new Counter(counterName);
			Assert.AreEqual(counterName, target.Info.Fullname);
		}

		/// <summary>
		/// Test for exception when creating a counter with empty counter name string.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentException))]
		public void Counter_ConstructorExceptionEmptyTest()
		{
			new Counter(String.Empty);
		}

		/// <summary>
		/// Test for exception when creating a counter with a null counter name string.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentException))]
		public void Counter_ConstructorExceptionNullTest()
		{
			new Counter(null);
		}

		/// <summary>
		/// Test for exception when creating a counter with a string name containing only a space.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentException))]
		public void Counter_ConstructorExceptionSpaceTest()
		{
			new Counter(" ");
		}

		/// <summary>
		/// Test for exception when assiging null to the counter values.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(NullReferenceException))]
		public void Counter_ValuesNullExceptionTest()
		{
			var target = new Counter(GeneratorCounterInfo.GenerateGenericCounterInfo(true));
			target.Values = null;
		}

		/// <summary>
		/// Test for exception when assigning an empty array for the values.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(NullReferenceException))]
		public void Counter_ValuesEmptyExceptionTest()
		{
			var target = new Counter(GeneratorCounterInfo.GenerateGenericCounterInfo(true));
			target.Values = new double[] { };
		}

		/// <summary>
		/// Test with a single value array.
		/// </summary>
		[TestMethod]
		public void Counter_ValuesSingleValueSizeTest()
		{
			TestForStaticArrays(Counter.SampleArraySize, 1);
		}

		/// <summary>
		/// Test with a SampleArraySize - 1 size static array.
		/// </summary>
		[TestMethod]
		[DeploymentItem("PerfAnalyzer.dll")]
		public void Counter_ValuesSampleArraySizeTest()
		{
			TestForStaticArrays(Counter.SampleArraySize - 1, 10);
		}

		/// <summary>
		/// Test with a SampleArraySize size static array.
		/// </summary>
		[TestMethod]
		[DeploymentItem("PerfAnalyzer.dll")]
		public void Counter_ValuesSampleArraySizeMinusOneTest()
		{
			TestForStaticArrays(Counter.SampleArraySize, 10);
		}

		/// <summary>
		/// Test with a SampleArraySize size static array.
		/// </summary>
		[TestMethod]
		[DeploymentItem("PerfAnalyzer.dll")]
		public void Counter_ValuesSampleArraySizePlusOneTest()
		{
			TestForStaticArrays(Counter.SampleArraySize + 1, 10);
		}

		/// <summary>
		/// Test function for counter creation with static value array assignement.
		/// </summary>
		/// <param name="arraySize">Size of the static array.</param>
		/// <param name="value">Value of the static array.</param>
		private void TestForStaticArrays(int arraySize, int value)
		{
			var target = new Counter(GeneratorCounterInfo.GenerateGenericCounterInfo(true));
			var expectedValues = GeneratorCounter.GenerateStaticArray(value, arraySize);

			// Test static array just in case
			Assert.AreEqual(arraySize, expectedValues.Length);

			target.Values = expectedValues;
			Assert.AreEqual(expectedValues.Length, target.Values.Length);
			if (arraySize < Counter.SampleArraySize)
				Assert.AreEqual(arraySize, target.SampledValues.Length);
			else
				Assert.AreEqual(Counter.SampleArraySize, target.SampledValues.Length);

			Assert.IsNotNull(target.Stats);

			Assert.AreEqual(value, target.Stats.Max);
			Assert.AreEqual(value, target.Stats.Min);
			Assert.AreEqual(value, target.Stats.Average);
			Assert.AreEqual(value, target.Stats.Percentile25th);
			Assert.AreEqual(value, target.Stats.Percentile50th);
			Assert.AreEqual(value, target.Stats.Percentile75th);
			Assert.AreEqual(value, target.Stats.Percentile90th);
			Assert.AreEqual(value, target.Stats.Percentile95th);
			Assert.AreEqual(value, target.Stats.Percentile99th);
			// TODO add standard deviation
		}
	}
}
